package com.yuyu.shop.application.service.tcc.impl;

import com.yuyu.commons.constant.BaseConstant;
import com.yuyu.commons.exception.BusinessException;
import com.yuyu.commons.interceptor.response.ResponseJson;
import com.yuyu.commons.toolKit.TccUtil;
import com.yuyu.shop.api.apimodel.order.dto.OrderCreateDTO;
import com.yuyu.shop.api.convert.OrderConvert;
import com.yuyu.shop.application.service.tcc.OrderAssembleTccService;
import com.yuyu.shop.domain.build.construct.NormalOrderConstruct;
import com.yuyu.shop.domain.order.DO.OrderCreateDO;
import com.yuyu.shop.domain.order.DO.OrderDO;
import com.yuyu.shop.domain.order.repository.TransactionalRecordRepository;
import com.yuyu.shop.infrastructure.persistence.po.TransactionalRecordPO;
import com.yuyu.storage.remote.IStorageRepositoryMicroService;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Objects;

/**
 * @author
 * @version 1.0
 * @description: tccService实现类
 * @date 2022/12/12 10:46
 */
@Service
@Slf4j
@AllArgsConstructor(onConstructor = @_(@Autowired))
public class OrderAssembleTccServiceImpl implements OrderAssembleTccService {

    private final TransactionalRecordRepository transactionalRecordRepository;

    private final IStorageRepositoryMicroService storageRepositoryMicroService;

    private final NormalOrderConstruct normalOrderConstruct;

    @Transactional
    @Override
    public OrderCreateDO tryCreate(BusinessActionContext businessActionContext, Integer orderType,
                             Long shopId, Long goodsId, Integer stockNum, String orderId) {
        log.info("事务id为{}",businessActionContext.getXid());
        TransactionalRecordPO record = transactionalRecordRepository.getByXid(businessActionContext.getXid());
        if (Objects.nonNull(record) && record.getStatus().equals(BaseConstant.THREE)){
            throw new BusinessException("已经进入cancel阶段,不允许try阶段!");
        }
        //冻结库存
        ResponseJson<Boolean> stockResponseJson = storageRepositoryMicroService.decStock(goodsId, Long.valueOf(stockNum));
        if (stockResponseJson.getCode().equals("0") && stockResponseJson.getData().equals(Boolean.FALSE)){
            throw new BusinessException("商品库存不足!");
        }
        //保证幂等性
        TccUtil.add(this.getClass(), businessActionContext.getXid(), System.currentTimeMillis());
        OrderCreateDTO orderCreateDTO = new OrderCreateDTO().setOrderType(orderType).setGoodsId(goodsId).setGoodsNum(stockNum).setShopId(shopId);
        OrderCreateDO construct = normalOrderConstruct.construct(orderCreateDTO);
        construct.setOrderId(Long.valueOf(orderId));
        //创建预订单
        OrderDO orderDO = OrderConvert.saveOrUpdateDTO2DO(construct);
        //状态为创建中
        if (Objects.isNull(orderDO)) {
           throw new BusinessException("订单创建失败!");
        }
        orderDO.setStatus(BaseConstant.ZERO);
        orderDO.saveOrUpdate();
        return construct;
    }

    @Transactional
    @Override
    public Boolean commit(BusinessActionContext businessActionContext) {
    log.info("开始第二阶段commit,事务id为{}", businessActionContext.getXid());
    //检验幂等性,防止多次提交
    if (Objects.isNull(TccUtil.get(this.getClass(), businessActionContext.getXid()))){
       return true;
    }
     //修改订单的状态
     String orderId = (String) businessActionContext.getActionContext("orderId");
     OrderDO byOrderId = OrderDO.getByOrderId(orderId);
     //修改订单状态 创建完成
     byOrderId.setOrderId(orderId).setStatus(BaseConstant.ONE).saveOrUpdate();
     //commit完成,移除事务map
     TccUtil.remove(this.getClass(), businessActionContext.getXid());
     return true;
    }

    @Transactional
    @Override
    public Boolean rollBack(BusinessActionContext businessActionContext) {
        //防止悬挂 需要保证幂等性
        TransactionalRecordPO transactionalRecordPO = new TransactionalRecordPO()
                .setXid(businessActionContext.getXid())
                //cancel阶段
                .setStatus(BaseConstant.THREE);
        transactionalRecordRepository.insert(transactionalRecordPO);
        // 空回滚
        if (Objects.isNull(TccUtil.get(this.getClass(), businessActionContext.getXid()))){
            return true;
        }
        log.info("第三阶段回滚,事务id为{}",businessActionContext.getXid());
        Integer goodsId =  (Integer) businessActionContext.getActionContext("goodsId");
        Long stockNum = (Long) businessActionContext.getActionContext("stockNum");
        //回滚冻结的库存
        storageRepositoryMicroService.rollBackStock(Long.valueOf(goodsId),stockNum);
        //rollback完成,移除事务map
        TccUtil.remove(this.getClass(), businessActionContext.getXid());
        return true;
    }
}
